use syn::Expr;
use syn::Result;

use crate::error::Error;

pub trait FromExpr: Sized {
    fn from_expr(expr: &Expr) -> Result<Self>;
}

impl FromExpr for Expr {
    fn from_expr(expr: &Expr) -> Result<Self> {
        Ok(expr.clone())
    }
}

impl FromExpr for Box<Expr> {
    fn from_expr(expr: &Expr) -> Result<Self> {
        Ok(Box::new(expr.clone()))
    }
}

impl FromExpr for syn::Lit {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            return Ok(lit.lit.clone());
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for syn::LitInt {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Int(lit_int) = &lit.lit {
                return Ok(lit_int.clone());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for syn::LitFloat {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Float(lit_float) = &lit.lit {
                return Ok(lit_float.clone());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for syn::LitBool {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Bool(lit_bool) = &lit.lit {
                return Ok(lit_bool.clone());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for syn::LitStr {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Str(lit_str) = &lit.lit {
                return Ok(lit_str.clone());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for syn::Path {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Path(path) = expr {
            return Ok(path.path.clone());
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}
